﻿using HalconDotNet;
using OPTSDK_Net;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using static OPTSDK_Net.OPTDefine;
using System.Windows.Forms;
using VisionRoc.Tool;

namespace VisionRoc.Core
{
    public class OPTVision
    {
        public OPTCamera My_Camera;
        private OPTSDK_Net.MyCamera cam = new OPTSDK_Net.MyCamera();
        object LockImage = new object();
        private OPTSDK_Net.OPTDefine.OPT_FrameCallBack frameCallBack;

        public OPTVision(string path, string CameraName, HWindowControl hWindow, out int IniCCDInfo)
        {
            HOperatorSet.GenEmptyObj(out Image);
            My_Camera = new OPTCamera(path);
            IniCCDInfo = InitCam(My_Camera.CAMERA_INIT_INFO);
            if (m_BInitCam == true)
            {
                if (Set_ExposureAndGain(My_Camera.Exposure, My_Camera.Gain))
                {
                    Global.AddLogInfoEvent(LogLevel.OK, $"相机初始化成功。曝光：{My_Camera.Exposure.ToString()}。增益：{My_Camera.Gain.ToString()}。设置成功");
                }
                else
                {
                    Global.AddLogInfoEvent(LogLevel.OK, $"相机初始化成功。曝光：{My_Camera.Exposure.ToString()}。增益：{My_Camera.Gain.ToString()}。设置成功");
                }
            }
            InitCamInfo(IniCCDInfo, CameraName);//显示CCD1 初始化信息
            HalconWindow(hWindow);
        }


        /// <summary>
        /// 读取图片计数
        /// </summary>
        public long IndexP;

        /// <summary>
        /// 当前图像
        /// </summary>
        public HObject Image;

        /// <summary>
        /// 1为触发
        /// </summary>
        public int Photo;

        /// <summary>
        /// 相机名称
        /// </summary>
        public string m_strName = "";

        /// <summary>
        /// 相机序列号 
        /// </summary>
        public string m_strSN = "";

        /// <summary>
        /// 相机型号
        /// </summary>
        public string m_strModel = "";

        /// <summary>
        /// 相机IP
        /// </summary>
        public string m_strIP = "";

        /// <summary>
        /// 相机标志位
        /// </summary>
        public bool m_BInitCam = false;

        /// <summary>
        /// 窗体控件
        /// </summary>
        public HWindowControl MyHwindow;

        /// <summary>
        /// 设备列表
        /// </summary>
        OPTDefine.OPT_DeviceList deviceList = new OPTDefine.OPT_DeviceList();

        /// <summary>
        /// 枚举设备
        /// </summary>
        /// <returns></returns>
        private int EnumDevice()
        {

            OPTDefine.OPT_EInterfaceType interfaceTp = OPTDefine.OPT_EInterfaceType.interfaceTypeAll;
            int res = OPTSDK_Net.MyCamera.OPT_EnumDevices(ref deviceList, (uint)interfaceTp);
            if (res != OPTDefine.OPT_OK)
            {
                return -1;
            }
            if (deviceList.nDevNum < 1)
            {
                return -1;
            }
            return res;
        }

        /// <summary>
        /// 初始化相机
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public int InitCam(string str)
        {
            m_BInitCam = false;
            if (My_Camera.CAMERA_STATE != 3)
            {
                return -1;
            }

            int res = OPTDefine.OPT_OK;
            if (EnumDevice() == -1)
            {
                return -2;
            }

            for (int i = 0; i < deviceList.nDevNum; i++)
            {
                OPTDefine.OPT_DeviceInfo deviceInfo = (OPTDefine.OPT_DeviceInfo)Marshal.PtrToStructure(deviceList.pDevInfo + Marshal.SizeOf(typeof(OPTDefine.OPT_DeviceInfo)) * i, typeof(OPTDefine.OPT_DeviceInfo));
                if (deviceInfo.nCameraType == OPTDefine.OPT_ECameraType.typeGigeCamera)
                {
                    if (deviceInfo.serialNumber == str)
                    {
                        OPTDefine.OPT_GigEDeviceInfo gigEDeviceInfo = (OPTDefine.OPT_GigEDeviceInfo)ByteToStruct(deviceInfo.deviceSpecificInfo.gigeDeviceInfo, typeof(OPTDefine.OPT_GigEDeviceInfo));
                        m_strSN = deviceInfo.serialNumber;

                        // 创建设备句柄
                        res = cam.OPT_CreateHandle(OPTDefine.OPT_ECreateHandleMode.modeByIndex, i);
                        if (res != OPTDefine.OPT_OK)
                        {
                            return -3;
                        }

                        // 打开相机设备 
                        res = cam.OPT_Open();
                        if (res != OPTDefine.OPT_OK)
                        {
                            return -4;
                        }

                        //关闭触发模式
                        res = OPTDefine.OPT_OK;
                        res = cam.OPT_SetEnumFeatureSymbol("TriggerMode", "Off");
                        if (OPTDefine.OPT_OK != res)
                        {
                            return -5;
                        }

                        //打开触发模式
                        res = OPTDefine.OPT_OK;
                        res = cam.OPT_SetEnumFeatureSymbol("TriggerMode", "On");
                        if (OPTDefine.OPT_OK != res)
                        {
                            return -6;
                        }

                        if (My_Camera.TRIGGER_MODEL == 1)
                        {
                            res = cam.OPT_SetEnumFeatureSymbol("TriggerSource", "Line1");
                            if (OPTDefine.OPT_OK != res)
                            {

                                return -7;
                            }
                        }

                        if (My_Camera.TRIGGER_MODEL == 2)
                        {
                            res = cam.OPT_SetEnumFeatureSymbol("TriggerSource", "Software");
                            if (OPTDefine.OPT_OK != res)
                            {
                                return -8;
                            }
                        }

                        if (!Set_ImageType(My_Camera.ImageType))
                        {
                            return -11;
                        }

                        // 注册数据帧回调函数
                        frameCallBack = onGetFrame;
                        res = cam.OPT_AttachGrabbing(frameCallBack, IntPtr.Zero);
                        if (res != OPTDefine.OPT_OK)
                        {
                            return -9;
                        }

                        // 开始拉流 
                        res = cam.OPT_StartGrabbing();
                        if (res != OPTDefine.OPT_OK)
                        {
                            Console.WriteLine("Start grabbing failed! ErrorCode:[{0}]", res);
                            return -10;
                        }

                        m_BInitCam = true;
                        return 0;
                    }
                }
            }
            return -12;
        }

        public static object ByteToStruct(Byte[] bytes, Type type)
        {
            int size = Marshal.SizeOf(type);
            if (size > bytes.Length)
            {
                return null;
            }

            // 分配结构体内存空间
            IntPtr structPtr = Marshal.AllocHGlobal(size);

            // 将byte数组拷贝到分配好的内存空间
            Marshal.Copy(bytes, 0, structPtr, size);

            // 将内存空间转换为目标结构体
            object obj = Marshal.PtrToStructure(structPtr, type);

            // 释放内存空间
            Marshal.FreeHGlobal(structPtr);

            return obj;
        }

        object o = new object();

        // 数据帧回调函数
        // Data frame callback function
        public void onGetFrame(ref OPTDefine.OPT_Frame frame, IntPtr pUser)
        {
            lock (o)
            {
                try
                {
                    uint nDstBufSize = 0;
                    nDstBufSize = frame.frameInfo.width * frame.frameInfo.height;
                    IntPtr pDstBuf = Marshal.AllocHGlobal((int)nDstBufSize);
                    if (frame.frameInfo.pixelFormat == OPT_EPixelType.gvspPixelRGB8)
                    {
                        Image.Dispose();
                        HOperatorSet.GenImageInterleaved(out Image, frame.pData, "rgb", frame.frameInfo.width,
                       frame.frameInfo.height, 0, "byte", frame.frameInfo.width, frame.frameInfo.height, 0, 0, 8, 0);
                    }
                    else if (frame.frameInfo.pixelFormat == OPT_EPixelType.gvspPixelMono8)
                    {
                        Image.Dispose();
                        HOperatorSet.GenImage1(out Image, "byte", frame.frameInfo.width, frame.frameInfo.height, frame.pData);
                    }
                    else
                    {
                        MyHOperatorSet.DispMeassge(MyHwindow.HalconWindow, $"相机未设置该图像类型：{frame.frameInfo.pixelFormat},SDK支持：Mono8,RGB8", "window", 10, 10, 20, "red");
                        return;
                    }


                    MyHwindow.HalconWindow.ClearWindow();
                    HTuple Width = new HTuple(), Height = new HTuple();
                    Width.Dispose(); Height.Dispose();
                    HOperatorSet.GetImageSize(Image, out Width, out Height);
                    MyHOperatorSet.SetHWindowPart(ref MyHwindow, Width, Height);
                    Image.DispObj(MyHwindow.HalconWindow);


                }
                catch (Exception ex)
                {
                    Global.AddLogInfoEvent(LogLevel.Error, "图像回调采集异常");
                    TxtAPI.WriteLogTxt($"图像回调采集异常:{ex.ToString()}");

                }

            }
        }

        /// <summary>
        /// 连续采集
        /// </summary>
        public void continuous()
        {
            try
            {
                if (cam.OPT_IsGrabbing())
                {
                    //关闭触发模式
                    int res = OPTDefine.OPT_OK;
                    res = cam.OPT_SetEnumFeatureSymbol("TriggerMode", "Off");
                    if (OPTDefine.OPT_OK != res)
                    {
                        Global.AddLogInfoEvent(LogLevel.Error, "Set Trigger Mode failed!");
                        return;
                    }
                }
                else
                {
                    MessageBox.Show("请查看相机是否打开");
                }
            }
            catch
            {
                // Global.AddLogInfo(LogLevel.Error, "连续采集方法异常！");
            }
        }

        /// <summary>
        /// 停止连续采集
        /// </summary>
        public void Stop()
        {
            try
            {
                if (cam.OPT_IsGrabbing())
                {
                    //关闭触发模式
                    //Close Trigger Mode
                    int res = OPTDefine.OPT_OK;
                    res = cam.OPT_SetEnumFeatureSymbol("TriggerMode", "On");
                    if (OPTDefine.OPT_OK != res)
                    {
                        Global.AddLogInfoEvent(LogLevel.Error, "Set Trigger Mode failed!");
                        return;
                    }
                }

            }
            catch
            {
                Global.AddLogInfoEvent(LogLevel.Error, "连续采集方法异常！");
            }


        }

        public void Trigger()
        {
            if (this != null)
            {
                if (My_Camera.CAMERA_STATE == 3)
                {
                    if (cam.OPT_IsGrabbing())
                    {
                        //发送一次触发命令
                        //Send Trigger Command
                        int res = OPTDefine.OPT_OK;
                        res = cam.OPT_ExecuteCommandFeature("TriggerSoftware");
                        if (OPTDefine.OPT_OK != res)
                        {
                            Global.AddLogInfoEvent(LogLevel.Error, "Execute TriggerSoftware failed!");
                            return;
                        }
                    }
                    else
                    {
                        Global.AddLogInfoEvent(LogLevel.Error, "请查看相机是否打开)");
                    }
                }
                else
                {
                    lock (o1)
                    {
                        OffLine_ReadImage();
                    }
                }

            }
        }

        object o1 = new object();
        /// <summary>
        /// 离线读取图像
        /// </summary>
        public void OffLine_ReadImage()
        {
            try
            {
                if (My_Camera.CAMERA_STATE != 3)
                {
                    if (My_Camera.CAMERA_STATE == 1)
                    {
                        lock (LockImage)
                        {
                            Image.Dispose();
                            HOperatorSet.ReadImage(out Image, My_Camera.OFFLINE_IMAGE_PATH);
                        }

                    }
                    else if (My_Camera.CAMERA_STATE == 2)
                    {
                        if (My_Camera.OFFLINE_IMAGE_FILE_PATH != "" && My_Camera.hv_ImageFiles != null)
                        {
                            if (My_Camera.hv_ImageFiles.TupleLength() > 0)
                            {
                                lock (LockImage)
                                {
                                    Image.Dispose();
                                    HOperatorSet.ReadImage(out Image, My_Camera.hv_ImageFiles.TupleSelect(IndexP));
                                    if (IndexP >= My_Camera.hv_ImageFiles.TupleLength() - 1)
                                    {
                                        IndexP = 0;
                                    }
                                    else
                                    {
                                        IndexP++;
                                    }

                                }
                            }
                        }
                    }

                    //if (Image == null && !MyHOperatorSet.ObjectValided(Image))
                    //{

                    //    return;
                    //}

                    MyHwindow.HalconWindow.ClearWindow();
                    HTuple Width = new HTuple(), Height = new HTuple();
                    Width.Dispose(); Height.Dispose();
                    HOperatorSet.GetImageSize(Image, out Width, out Height);
                    MyHOperatorSet.SetHWindowPart(ref MyHwindow, Width, Height);
                    Image.DispObj(MyHwindow.HalconWindow);
                    //  MyHOperatorSet.DispMeassge(MyHsmart.HalconWindow, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff"), "window", 10, 10, 15, "green");
                    //if (Global.RunState == 1)
                    //{
                    //    Photo = 1;
                    //}
                }
                else
                {

                }
            }
            catch { }


        }

        /// <summary>
        /// 设置曝光与增益
        /// </summary>
        /// <param name="exposure"></param>
        /// <param name="gain"></param>
        /// <returns></returns>
        public bool Set_ExposureAndGain(double exposure, double gain)
        {
            int res;
            if (false == cam.OPT_IsOpen())
            {
                MessageBox.Show("Device is not connect!");
                return false;
            }
            // 设置曝光值
            // set ExposureTime 
            res = cam.OPT_SetDoubleFeatureValue("ExposureTime", exposure);
            if (OPTDefine.OPT_OK != res)
            {
                return false;
                //  MessageBox.Show("set exposuretime fail!");
            }

            // 设置增益 
            // set Gain 
            res = cam.OPT_SetDoubleFeatureValue("Gain", gain);
            if (OPTDefine.OPT_OK != res)
            {
                return false;
                // MessageBox.Show("set gain fail!");
            }
            return true;
        }

        /// <summary>
        /// 设置图像格式
        /// </summary>
        /// <param name="PixelType"></param>
        public bool Set_ImageType(string PixelType)
        {
            int res;
            //设置图像格式
            // set Pixel Type
            if (true == cam.OPT_IsOpen() && false == cam.OPT_IsGrabbing())
            {
                string pixelType = PixelType;
                res = cam.OPT_SetEnumFeatureSymbol("PixelFormat", pixelType);
                if (OPTDefine.OPT_OK != res)
                {
                    return false;
                }
                return true;
            }
            return false;
        }

        /// <summary>
        /// 返回窗体控件
        /// </summary>
        /// <param name="hSmart"></param>
        /// <returns></returns>
        public void HalconWindow(HWindowControl Hwindow)
        {
            MyHwindow = Hwindow;
        }

        /// <summary>
        /// 关闭相机
        /// </summary>
        /// <returns></returns>
        public bool Close_Camera()
        {
            if (cam != null)
            {
                //关闭相机
                //Close camera 
                int res = cam.OPT_Close();
                if (res != OPTDefine.OPT_OK)
                {
                    return false;
                }

                // 销毁设备句柄
                // Destroy Device Handle
                res = cam.OPT_DestroyHandle();
                if (res != OPTDefine.OPT_OK)
                {
                    return false;
                }
                return true;
            }
            return false;
        }

        /// <summary>
        /// 相机初始化信息
        /// </summary>
        /// <param name="X"></param>
        /// <param name="CCD"></param>
        public void InitCamInfo(int X, string CCD)
        {
            switch (X)
            {
                case -1:
                    Global.AddLogInfoEvent(LogLevel.Info, $"【{CCD}】 相机离线模式！");
                    break;
                case -2:
                    Global.AddLogInfoEvent(LogLevel.Error, $"【{CCD}】 没有枚举到相机！");
                    break;
                case -3:
                    Global.AddLogInfoEvent(LogLevel.Error, $"【{CCD}】 相机句柄创建失败！");
                    break;
                case -4:
                    Global.AddLogInfoEvent(LogLevel.Error, $"【{CCD}】 相机打开失败！");
                    break;
                case -5:
                    Global.AddLogInfoEvent(LogLevel.Error, $"【{CCD}】 相机关闭触发模式失败");
                    break;
                case -6:
                    Global.AddLogInfoEvent(LogLevel.Error, $"【{CCD}】 相机打开触发模式失败！");
                    break;
                case -7:
                    Global.AddLogInfoEvent(LogLevel.Error, $"【{CCD}】 相机设置外触发失败！");
                    break;
                case -8:
                    Global.AddLogInfoEvent(LogLevel.Error, $"【{CCD}】 设置软触发失败！");
                    break;
                case -9:
                    Global.AddLogInfoEvent(LogLevel.OK, $"【{CCD}】 注册回调失败！");
                    break;
                case -10:
                    Global.AddLogInfoEvent(LogLevel.OK, $"【{CCD}】 开始取流失败！");
                    break;
                case -11:
                    Global.AddLogInfoEvent(LogLevel.OK, $"【{CCD}】 图像类型设置失败！");
                    break;
                case -12:
                    Global.AddLogInfoEvent(LogLevel.OK, $"【{CCD}】:{m_strSN}  没有找到该序列号相机 ");
                    break;
                case 0:
                    Global.AddLogInfoEvent(LogLevel.OK, $"【相机序列号为:{m_strSN}】 初始化成功！");
                    break;
            }
        }

        ~OPTVision()
        {
            Close_Camera();
        }
    }
}
